#!/bin/bash
#Psync - GPL - Robert Lane (tasmod). npierce 2013
#Synchronises system and hardware clock to a public time server

#exec &>/tmp/${0##*/}.log ; set -x ; env #debug

set_time_from_server() {
	echo "* Synchronizing with time server..."
	if ntpdate pool.ntp.org &> /tmp/settertime ; then
		echo "* Success..."
	else
		"* ERROR..."
		return 1
	fi
	date
	set_hwclock_type -q --systohc #system time to hw
	if [ $? -ne 0 ] ; then
		echo "* Could not set hardware clock..."
	fi
	touch ${SYSROOT}/var/tmp/psync_done
	return 0
}

#==============================================================
#                    SERVICE
#==============================================================
case $1 in
	start|restart)
		CONNECTED=no
		for i in $(seq 0 5 300) ; do
			if [ "$(LANG=C route -n | awk 'FNR == 3 {print $2}')" != "0.0.0.0" ] && \
				grep -wq nameserver ${SYSROOT}/etc/resolv.conf ; then
				CONNECTED=yes
				break
			fi
			sleep 5
		done
		if [ "$CONNECTED" = "no" ] ; then
			exit 1
		fi
		set_time_from_server
		exit $?
		;;
	stop)
		exit
		;;
esac
#==============================================================


#==============================================================
#                          APP
#==============================================================

PSYNC_ENABLED=false
if [ -x ${SYSROOT}/etc/init.d/psync ] ; then
	PSYNC_ENABLED=true
fi

psync_status() {
	if [ "$PSYNC_ENABLED" = "true" ] ; then
		echo "psync autostart is enabled..."
		return 0
	else
		echo "psync autostart is disabled..."
		return 1
	fi
}

enable_psync() {
	if [ ! -f ${SYSROOT}/etc/init.d/psync ] ; then
		echo '#!/bin/sh
case $1 in start|restart|stop)
	/usr/sbin/psync $1 1>/dev/null 2>&1 &
esac' > ${SYSROOT}/etc/init.d/psync
	fi
	chmod +x ${SYSROOT}/etc/init.d/psync
	[ ! "$GUI" ] && echo "psync autostart on bootup enabled"
}
disable_psync() {
	chmod -x ${SYSROOT}/etc/init.d/psync
	#rm -f ${SYSROOT}/etc/init.d/psync
	[ ! "$GUI" ] && echo "psync autostart on bootup disabled"
}

set_tz() {
	if [ ! "$1" ] ; then
		echo "You must specify a timezone."
		return 1
	fi
	if [ -f ${SYSROOT}/usr/share/zoneinfo/$1 ] ; then
		ln -snfv /usr/share/zoneinfo/$1 ${SYSROOT}/etc/localtime
		return $?
	else
		echo "File not found: ${SYSROOT}/usr/share/zoneinfo/$1"
		return 1
	fi
}

usage() {
	app=${0##*/}
	echo
	echo "  synchronize system and hardware clock to a public timeserver.."
	echo
	echo "usage: $app <option>"
	echo
	echo "Options:"
	echo " -cli           : force cli"
	echo " -gui           : force gui"
	echo " -sysroot <dir> : set root dir"
	echo " -autostart     : enable service"
	echo " -noautostart   : disable service"
	echo " -status        : report service status"
	echo " -sync          : sync with time server"
	echo " -timezone <tz> : set timezone"
	echo
}

[ "$DISPLAY" ] && export GUI=1

for i in $@; do
	case $1 in
		-sysroot)     export SYSROOT=$2 ; shift ;;
		-autostart)   enable_psync  ; exit $? ;;
		-noautostart) disable_psync ; exit $? ;;
		-status)      psync_status  ; exit $? ;;
		-timezone)    set_tz $2     ; exit $? ;;
		-sync)        set_time_from_server ; exit $? ;;
		-h|-help|--help) usage; exit ;;
		-cli|cli) GUI=  ;;
		-gui|gui) export GUI=1 ;;
		*) echo "unknown option: $1" ; usage ; exit 1 ;;
	esac
	shift
done

#==============================================================
#                          CLI
#==============================================================

dlg() {
	local ret file=/tmp/psync$$
	dialog --backtitle "pSync - $(date)" "$@" >/dev/tty 2> $file
	ret=$?
	retstr="$(cat $file)" # can be multiple lines
	rm -f $file
	return $ret
}

msgbox() { dlg --msgbox "$*" 0 0 ; }
infobox() { dlg --infobox "$*" 0 0 ; }

if [ ! "$GUI" ] ; then
	while [ 1 ] ; do
		if psync_status >/dev/null ; then
			st=enabled
		else
			st=disabled
		fi
		zi=$(readlink /etc/localtime | sed 's%/usr/share/zoneinfo/%%')
		eval dlg --menu "'pSync - autostart $st - $zi'" 0 0 0 \
			autostart   "'enable service on bootup'" \
			noautostart "'disable service'" \
			timezone    "'set timezone...'" \
			sync        "'sync with timeserver'" \
			exit "'$(gettext 'Exit')'" || exit
		case $retstr in
			autostart) enable_psync ; sleep 3 ;;
			noautostart) disable_psync ; sleep 3 ;;
			timezone) timezone-set cli ;;
			sync) set_time_from_server ; sleep 5 ;;
			exit) exit ;;
		esac
	done
	exit
fi

#==============================================================
#                          GUI
#==============================================================

export -f enable_psync
export -f disable_psync
export psync_chkbox=' <checkbox>
          <label>'$(gettext 'Synchronise at startup (autostart)')'</label>
          <default>'${PSYNC_ENABLED}'</default>
          <variable>PSYNC_ENABLED</variable>
          <action>if true enable_psync</action>
          <action>if false disable_psync</action>
        </checkbox>
'

function synchronise_clock() {
	if [ ! -f /var/tmp/psync_done ] ; then
		/usr/lib/gtkdialog/box_yesno --ok-cancel --no-first --yes-label Sync --info "Psync" "Confirm action..." "(if in doubt click on the Help button...)"
		[ $? -ne 0 ] && return
	fi
	/usr/lib/gtkdialog/box_splash -close never -text "$(printf "$(gettext 'Please wait...')")" &
	X1PID=$!
	set_time_from_server
	if [ $? -ne 0 ] ; then
		kill $X1PID
		/usr/lib/gtkdialog/box_ok "Psync" error "$(gettext 'Error synchronizing with NTP server')"
		exit 1
	fi
	kill $X1PID
	NEWCURRENT_TIME=`date +%c`
	secs=`cat /tmp/settertime | tail -2 | grep 'offset'`
	offset=${secs#*offset}
	#=
	cd $HOME
	export timeis='<window title="Synchronised System Time" image-name="/usr/share/pixmaps/puppy/clock_countdown.svg">
    <vbox>
      <frame Updated Time>
        <text use-markup="true"><label>"<b>'${NEWCURRENT_TIME}'</b>"</label></text>
	    <text><label>"       "</label></text>
	    <text use-markup="true"><label>" <b>  Offset was '${offset}'      </b>"</label></text>
	  </frame>
      <frame>
        <text><label> To synchronise your clock at each startup. </label></text>
        <text><label>Press the button for auto run at each startup.</label></text>
        '${psync_chkbox}'
        <text><label>"       "</label></text>
        <hbox>
          <button space-expand="true" space-fill="true">
            <label>'$(gettext "Show main dialog")'</label>
            <action>EXIT:0</action>
          </button>
          <button space-expand="true" space-fill="true">
            <label>'$(gettext "Quit")'</label>
            '"`/usr/lib/gtkdialog/xml_button-icon quit`"'
            <action>EXIT:quit</action>
          </button>
        </hbox>
      </frame>
    </vbox>
</window>'

	#execute gtkdialog
	eval "$(gtkdialog -c -p timeis)"
	[ "$EXIT" = "quit" ] && return 10
}
export -f synchronise_clock
case $1 in synchronise_clock|set)
	shift
	synchronise_clock "$@"
	exit ;;
esac
#=========================================================

#Add services for ntp
if [ ! "`grep 'ntp 123/tcp' /etc/services`" ] ; then
	echo -e "ntp 123/tcp\nntp 123/udp" >> /etc/services
fi

#DST report variables
YEAR=`date +%Y`
#Read hwclock --debug and send to temp file
hwclock --debug | tail -5 > /tmp/psyncreport 
CURRENT_DATE=`cat /tmp/psyncreport | grep 'Time read from Hardware Clock:' | cut -d " " -f6-` 
CURRENT_HW=`cat /tmp/psyncreport | tail -1 `
CURRENT_TIME=`date +%X%t%Z`
OFF=`date +%z`

help_box() {
	echo  "<b>GMT-/+ time zones</b>
If you use a GMT timezone with offset then the top line hardware report will show the offset in reverse notation. 
After setting the time there is an option to run Psync automatically at each startup.

<b>Set timezone..</b>
Use this to set a proper time zone

<b>Synchronise to time server</b>
For this to work as expected, you should have already selected a proper timezone for your location.

<b>The time is wrong</b>
And more importantly, if the time is wrong.. try not using a GMT* timezone, but a more specific one: America/... Asia/... Africa/... Europe/...
" > /tmp/box_help
	/usr/lib/gtkdialog/box_help Psync
}
export -f help_box


cd $HOME
WELCOME_MSG=$(/usr/lib/gtkdialog/xml_info fixed clock_countdown.svg 25 "$(gettext 'Psync synchronises system and hardware clock to a public time server')")
export Psync='
<window title="Psync Time Server Synchroniser" image-name="/usr/share/pixmaps/puppy/clock.svg">
 <vbox>
   '${WELCOME_MSG}'
   <hbox space-expand="true" space-fill="true">
     '${psync_chkbox}'
   </hbox>
   <frame ------------System Time & Offset to current Hardware Clock>
     <text use-markup="true"><label>"<b>'${CURRENT_HW}'</b>"</label></text>
   </frame>
   <frame -------------------------------Hardware Time >
     <text use-markup="true"><label>"<b>'${CURRENT_DATE}'</b>"</label></text>
   </frame>

   <hbox>
     <frame ------------Time Zone set as :->
       <text use-markup="true"><label>"<b>'`readlink /etc/localtime | sed -e 's%^.*share/zoneinfo/%%'`'</b>"</label></text>
     </frame>
     <frame ----------True Offset to UTC>
       <text use-markup="true"><label>"<b>'${OFF}'</b>"</label></text>
     </frame>
   </hbox>

   <hbox>
      <button space-expand="false" space-fill="false">
        '"`/usr/lib/gtkdialog/xml_button-icon help`"'
        <label>"'$(gettext 'Help')'"</label>
        <action>help_box &</action>
      </button>

      <button space-expand="false" space-fill="false">
         <label>'$(gettext "Set timezone...")'</label>
         '"`/usr/lib/gtkdialog/xml_button-icon country_timezone.svg icon`"'
         <action>exit:set_timezone</action>
      </button>
      <button space-expand="false" space-fill="false">
         <label>'$(gettext "Sync to time server")'</label>
         '"`/usr/lib/gtkdialog/xml_button-icon clock_countdown.svg`"'
         <action>exit:sync</action>
      </button>
      <button space-expand="false" space-fill="false">
         <label>'$(gettext "Quit")'</label>
         '"`/usr/lib/gtkdialog/xml_button-icon quit`"'
         <action>EXIT:quit</action>
      </button>
   </hbox>
 </vbox>
</window>'

#execute gtkdialog
. /usr/lib/gtkdialog/xml_info gtk
eval "$(gtkdialog -c -p Psync)"

if [ "$EXIT" = "set_timezone" ] ; then
	timezone-set
	exec $0
elif [ "$EXIT" = "sync" ] ; then
	synchronise_clock
	[ $? -eq 10 ] && exit #quit
	exec $0
fi

### EOF ###